﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using System.IO;

namespace SplenetiX
{
    [Serializable]
    public class Level
    {
        Tile[,] tiles;
        public char[,] bisouxchar;
        int level_length = 0;
        int level_height = 0;
        //float previousBottom;
        int Num;
        float gravity = Constant.Gravity;

        List<Ennemi> ennemis;
        public List<Ennemi> Ennemis { get { return ennemis; } }
        public float Gravity { get { return gravity; } }

        public Level()
        {
            ennemis = new List<Ennemi>();
        }

        public Level(int num)
        {
            ennemis = new List<Ennemi>();
            Num = num;
        }

        public int Longueur
        {
            get { return level_length; }
            set { this.level_length = value; }
        }

        public int Hauteur
        {
            get { return level_height; }
            set { this.level_height = value; }
        }

        public int Numero
        {
            get { return Num; }
            set { this.Num = value; }
        }


        public void InitTailleLevel()
        {
            string path = "map_" + Numero + ".txt";
            path = Path.Combine(StorageContainer.TitleLocation, "Content/" + path);

            StreamReader sr = new StreamReader(path);

            string line;
            for (level_height = 0; ((line = sr.ReadLine()) != null); level_height++)
            {
                level_length = line.Length;
            }

            tiles = new Tile[level_length, level_height];

            sr.Close();
        }

        //Charge des parametres contenus dans un fichier map_x.aux
        public void ConfigLevel()
        {
            string path = "map_" + Numero + ".aux";
            path = Path.Combine(StorageContainer.TitleLocation, "Content/" + path);
            if (File.Exists(path))
            {
                StreamReader sr = new StreamReader(path);
                gravity = float.Parse(sr.ReadLine().Substring(10)); //gravity = x
                sr.Close();
            }
        }

        public void Parser(ContentManager content)
        {
            string[] strArray = new string[Longueur];
            char[,] T = new char[Longueur, Hauteur];
            int i = 0;
            int j = 0;
            bool firstBlockX = true;
            
            // Recuperation fichier sous forme d'un tableau de string
            try
            {
                string path2 = "map_" + Numero + ".txt";
                path2 = Path.Combine(StorageContainer.TitleLocation, "Content/" + path2);

                StreamReader sr = new StreamReader(path2);
                String line;
                for (i = 0; ((line = sr.ReadLine()) != null); i++)
                {
                    strArray[i] = line;
                    for (j = 0; j < Longueur; j++)
                    {
                        T[j, i] = line[j];
                    }
                }
            }
            catch (Exception e)
            {
                throw new Exception(String.Format("{0} Exception caught.", e));
                //strArray = null;
            }


            /*Test shubham,*/
            bisouxchar = T; 

            // Ajout listes
            for (j = 0; j < Hauteur; j++)
            {

                for (i = 0; i < Longueur; i++)
                {
                    ParseBlocks(T, i, j, '#', "", ref firstBlockX, content); // Blocs Normaux
                    ParseBlocks(T, i, j, 'A', "acier_", ref firstBlockX, content); // Blocs Acier
                    ParseBlocks(T, i, j, 'G', "or_", ref firstBlockX, content); // Blocs Or
                    ParseBlocks(T, i, j, 'S', "destroy_", ref firstBlockX, content); // Blocs destroy

                    if (T[i, j] == '.')
                    {
                        firstBlockX = true;
                    }

                    if (T[i, j] == 'B')
                    {
                        tiles[i, j] = new Tile(i * 32, j * 32, content, "Tiles&Background//bidon", TileCollision.Passable);
                    }

                    //Point d'entree du niveau
                    if (T[i, j] == 'E')
                    {
                        Constant.EntryPoint = new Vector2(i * Constant.TileSize, j * Constant.TileSize);
                    }

                    if (T[i, j] == '&')
                    {
                        tiles[i, j] = new Tile(i * 32 - 60, j * 32 - 35, content, "Tiles&Background//exit", TileCollision.Passable);
                        Constant.EndPoint = new Vector2(i * Constant.TileSize, j * Constant.TileSize);
                    }

                    //Generation des ennemis
                    if (T[i, j] == '1')
                    {
                        AddEnnemi(new Vector2(i * Constant.TileSize, j * Constant.TileSize));
                    }
                }
                firstBlockX = false;
            }

            
            for (int k = 0; k < Hauteur; k++)
            {
                for (int l = 0; l < Longueur; l++)
                {
                    if (tiles[l, k] == null)
                        tiles[l, k] = new Tile(new Vector2(l * 32, k * 32));
                }
            }

        }

        public void ParseBlocks(char[,] T, int i, int j, char charTile, string typeTile, ref bool firstBlockX, ContentManager content)
        {
            if (T[i, j] == charTile)
            {
                if (((firstBlockX && (i < Longueur - 1) && (T[i + 1, j] != charTile)) || (firstBlockX && i == Longueur - 1))
                    && ((j > 0 && (T[i, j - 1] != charTile) && (T[i, j + 1] != charTile)) || (j == 0 && (T[i, j + 1] != charTile))))
                {
                    tiles[i, j] = new Tile(i * 32, j * 32, content, "Tiles&Background//bloc_" + typeTile + "seul", TileCollision.Impassable);
                    firstBlockX = false;
                }

                else if (((firstBlockX && (i < Longueur - 1) && (T[i + 1, j] != charTile) || (firstBlockX && i == Longueur - 1))
                    && ((j > 0 && (T[i, j - 1] != charTile) && (T[i, j + 1] == charTile)) || (j == 0 && (T[i, j + 1] == charTile)))))
                {
                    tiles[i, j] = new Tile(i * 32, j * 32, content, "Tiles&Background//bloc_" + typeTile + "Hseul", TileCollision.Impassable);
                    firstBlockX = false;
                }

                else if ((((i < Longueur - 1) && i > 0))
                    && (((j < Hauteur) && j > 0 && (T[i, j - 1] == charTile) && (T[i + 1, j] == charTile) && (T[i + 1, j - 1] != charTile))))
                {
                    tiles[i, j] = new Tile(i * 32, j * 32, content, "Tiles&Background//bloc_" + typeTile + "BC", TileCollision.Impassable);
                    firstBlockX = false;
                }

                else if ((((i < Longueur - 1) && i > 0 && (T[i + 1, j] != charTile)))
                    && (((j < Hauteur - 1) && j > 0 && (T[i, j + 1] != charTile) && (T[i, j - 1] == charTile))))
                {
                    tiles[i, j] = new Tile(i * 32, j * 32, content, "Tiles&Background//bloc_" + typeTile + "BD", TileCollision.Impassable);
                    firstBlockX = false;
                }

                else if (((!firstBlockX && (i < Longueur - 1) && (T[i + 1, j] == charTile)) || (!firstBlockX && i == Longueur - 1))
                    && ((j > 0 && (T[i, j - 1] != charTile)) || (j == Hauteur - 1 && T[i, j - 1] != charTile)))
                {
                    tiles[i, j] = new Tile(i * 32, j * 32, content, "Tiles&Background//bloc_" + typeTile + "milieu", TileCollision.Impassable);
                    firstBlockX = false;
                }

                else if (((firstBlockX && (i < Longueur - 1) && (T[i + 1, j] == charTile))
                    && ((j > 0 && (T[i, j - 1] != charTile)))))
                {
                    tiles[i, j] = new Tile(i * 32, j * 32, content, "Tiles&Background//bloc_" + typeTile + "HG", TileCollision.Impassable);
                    firstBlockX = false;
                }

                else if (((!firstBlockX && (i < Longueur - 1) && i > 0 && (T[i - 1, j] == charTile) && (T[i + 1, j] != charTile)) || (!firstBlockX && i == Longueur - 1))
                    && (((j < Hauteur - 1) && j > 0 && (T[i, j - 1] != charTile) && (T[i, j + 1] == charTile)) || (j == 0 && T[i, j + 1] == charTile)))
                {
                    tiles[i, j] = new Tile(i * 32, j * 32, content, "Tiles&Background//bloc_" + typeTile + "HD", TileCollision.Impassable);
                    firstBlockX = false;
                }

                else if (((!firstBlockX && (i < Longueur - 1) && i > 0 && (T[i - 1, j] == charTile) && (T[i + 1, j] != charTile)) || (!firstBlockX && i == Longueur - 1))
                    && (((j < Hauteur - 1) && j > 0 && (T[i, j - 1] != charTile) && (T[i, j + 1] != charTile)) || (j == Hauteur - 1 && T[i, j - 1] != charTile) || (j == 0 && T[i, j + 1] != charTile)))
                {
                    tiles[i, j] = new Tile(i * 32, j * 32, content, "Tiles&Background//bloc_" + typeTile + "LD", TileCollision.Impassable);
                    firstBlockX = false;
                }


                else if ((((i < Longueur - 1) && i > 0 && (T[i + 1, j] != charTile)))
                    && (((j < Hauteur - 1) && j > 0 && (T[i, j - 1] == charTile))))
                {
                    tiles[i, j] = new Tile(i * 32, j * 32, content, "Tiles&Background//bloc_" + typeTile + "CD", TileCollision.Impassable);
                    firstBlockX = false;
                }

                else
                {
                    tiles[i, j] = new Tile(i * 32, j * 32, content, "Tiles&Background//bloc_" + typeTile + "centre", TileCollision.Impassable);
                    firstBlockX = false;
                }
            }
        }

        public void DrawLevel(SpriteBatch spriteBatch)
        {
            
            //Draw ennemies
            foreach (Ennemi e in ennemis)
            {
                e.DrawEnnemi(spriteBatch);
            }

                        
            //Draw tiles
            for (int i = 0; i < tiles.GetLength(0); i++)
            {
                for (int j = 0; j < tiles.GetLength(1); j++)
                {
                    tiles[i, j].DrawTile(spriteBatch);
                }
            }

           
        }

        public void GlobalCollision(List<Personnage> personnages)
        {
            foreach (Character p in personnages)
            {
                Collision(p);
            }
        }


        private void Collision(Character character)
        {
            character.IsOnGround = false;

            Rectangle rectJoueur = new Rectangle((int)character.Position.X, (int)character.Position.Y, character.Texture.Width, character.Texture.Height);

            int leftTile = (int)Math.Floor((float)rectJoueur.Left / Constant.TileSize);
            int rightTile = (int)Math.Ceiling(((float)rectJoueur.Right / Constant.TileSize)) - 1;
            int topTile = (int)Math.Floor((float)rectJoueur.Top / Constant.TileSize);
            int bottomTile = (int)Math.Ceiling(((float)rectJoueur.Bottom / Constant.TileSize)) - 1;

            for (int i = 0; i < tiles.GetLength(0); i++)
            {
                for (int j = 0; j < tiles.GetLength(1); j++)
                {
                    #region platformer

                    if (tiles[i, j].Collision != TileCollision.Passable)
                    {
                        Rectangle rectBlock = new Rectangle(i * 32, j * 32, Constant.TileSize, Constant.TileSize);
                        Vector2 depthInter = Vector2.Zero;

                        float distanceX = rectJoueur.Center.X - rectBlock.Center.X;
                        float distanceY = rectJoueur.Center.Y - rectBlock.Center.Y;
                        float distanceMinX = (rectJoueur.Width + rectBlock.Width) / 2;
                        float distanceMinY = (rectJoueur.Height + rectBlock.Height) / 2;

                        if (Math.Abs(distanceX) <= distanceMinX && Math.Abs(distanceY) <= distanceMinY)
                        {
                            float depthX = distanceX > 0 ? distanceMinX - distanceX : -distanceMinX - distanceX;
                            float depthY = distanceY > 0 ? distanceMinY - distanceY : -distanceMinY - distanceY;

                            depthInter = new Vector2(depthX, depthY);

                            float absDepthX = Math.Abs(depthInter.X);
                            float absDepthY = Math.Abs(depthInter.Y);

                            /*if (depthY > 0 && !joueur.IsOnGround && tiles[i, j].Collision == TileCollision.Impassable)
                            {
                                joueur.Position = new Vector2(joueur.Position.X, rectBlock.Bottom);
                                joueur.IsJumping = false;
                            }
                            // Resolve the collision along the shallow axis.
                            else */
                            if (absDepthY <= absDepthX || tiles[i, j].Collision == TileCollision.Platform)
                            {
                                // If we crossed the top of a tile, we are on the ground.
                                if (character.PreviousBottom <= rectBlock.Top)
                                    character.IsOnGround = true;


                                // Ignore platforms, unless we are on the ground.
                                if (tiles[i, j].Collision == TileCollision.Impassable || character.IsOnGround)
                                {
                                    // Resolve the collision along the Y axis.
                                    character.Position = new Vector2(character.Position.X, character.Position.Y/*- absDepthY);*/ + depthInter.Y);

                                    // Perform further collisions with the new bounds.
                                    rectJoueur = new Rectangle((int)character.Position.X, (int)character.Position.Y, character.Texture.Width, character.Texture.Height);
                                }

                            }
                            else if (tiles[i, j].Collision == TileCollision.Impassable) // Ignore platforms.
                            {
                                // Resolve the collision along the X axis.
                                if (character.Type != CharacterType.Ennemi)
                                {
                                    character.Position = new Vector2(character.Position.X + depthInter.X, character.Position.Y);
                                }

                                // Perform further collisions with the new bounds.
                                rectJoueur = new Rectangle((int)character.Position.X, (int)character.Position.Y, character.Texture.Width, character.Texture.Height);
                            }

                            if (tiles[i, j].Collision == TileCollision.Impassable && !character.IsOnGround && absDepthX >= absDepthY)
                            {
                                character.Vitesse = new Vector2(character.Vitesse.X, 0);
                                character.IsJumping = false;
                            }
                        }
                    }

                    if (character.Type == CharacterType.Ennemi)
                    {
                        Rectangle rectBlock = new Rectangle((int)tiles[i, j].Position.X, (int)tiles[i, j].Position.Y, Constant.TileSize, Constant.TileSize);
                        Rectangle rectInter = Rectangle.Intersect(rectJoueur, rectBlock);

                        character.IA(this);

                        if (rectInter.Height == Constant.TileSize && tiles[i, j].Collision == TileCollision.Impassable)
                        {                            
                            character.StopFollow();
                            //character.Direction = -character.Direction;
                        }
                    }
                    #endregion

                    #region Collision des projectiles
                    for (int z = 0; z < character.Projectiles.Count; z++)
                    {
                        if (tiles[i, j].Collision != TileCollision.Passable && character.Projectiles[z].Rectangle.Intersects(tiles[i, j].Rectangle))
                        {
                            character.Projectiles.RemoveAt(z);
                        }
                    }
                    #endregion
                }
            }

            // Save the new bounds bottom.
            character.PreviousBottom = rectJoueur.Bottom;
        }

        /*
        public void Collision(Ennemi ennemi)
        {
            Rectangle rectEnnemi = new Rectangle((int)ennemi.Position.X, (int)ennemi.Position.Y, ennemi.Texture.Width, ennemi.Texture.Height);

            for (int i = 0; i < tiles.GetLength(0); i++)
            {
                for (int j = 0; j < tiles.GetLength(1); j++)
                {
                    Rectangle rectBlock = new Rectangle((int)tiles[i, j].Position.X, (int)tiles[i, j].Position.Y, Constant.TileSize, Constant.TileSize);
                    Rectangle rectInter = Rectangle.Intersect(rectEnnemi, rectBlock);

                    #region Collision des projectiles
                    for (int z = 0; z < ennemi.Projectiles.Count; z++)
                    {
                        if (tiles[i,j].Collision != TileCollision.Passable && ennemi.Projectiles[z].Rectangle.Intersects(tiles[i, j].Rectangle))
                        {
                            ennemi.Projectiles.RemoveAt(z);
                        }
                    }
                    #endregion

                    if (rectInter.Height == Constant.TileSize && tiles[i, j].Collision == TileCollision.Impassable)
                    {
                        //ennemi.IsFollowing = false;
                        ennemi.StopFollow();
                        ennemi.Direction = -ennemi.Direction;
                    }
                }
            }
        }
        */

        public void AddEnnemi(Vector2 position)
        {
            Random rand = new Random();
            ennemis.Add(new Ennemi(position, Constant.BasicHealth + rand.Next(-5, 5)));
        }

        public void Load(ContentManager content)
        {
            foreach (Ennemi e in ennemis)
            {
                // on  load chaque ennemi
                e.Load(content);
            }
        }

        public void Update(GameTime gameTime, Personnage joueur)
        {
            
            for (int i = 0; i < ennemis.Count; i++)
            {
                if (ennemis[i].Health <= 0)
                {
                    SoundEngine.PlaySound(SoundEngine.Mort_Ennemi);
                    ennemis.RemoveAt(i);
                }
                else
                {
                    ennemis[i].Deplacement(joueur, gameTime);
                    Collision(ennemis[i]);
                    ennemis[i].Update(gameTime, joueur,this);
                }
            }

        }

        public void ResetEnnemis()
        {
            ennemis.Clear();
        }
        
    }
}